package com.maiji.cloud.service.impl;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.baomidou.mybatisplus.plugins.Page;
import com.google.common.collect.Lists;
import com.maiji.cloud.config.MyRedisConfig;
import com.maiji.cloud.entities.login.AppUser;
import com.maiji.cloud.entities.login.RecipeThumbsUpOrCollection;
import com.maiji.cloud.entities.shopingmall.Goods;
import com.maiji.cloud.entities.shopingmall.GoodsCollection;
import com.maiji.cloud.mapper.GoodsCollectionMapper;
import com.maiji.cloud.microservice.UserInfoService;
import com.maiji.cloud.request.ReqMetaData;
import com.maiji.cloud.response.BaseMetaResDto;
import com.maiji.cloud.response.BaseResDto;
import com.maiji.cloud.response.ResMetaData;
import com.maiji.cloud.response.Status;
import com.maiji.cloud.response.shopingmall.GoodsResData;
import com.maiji.cloud.service.GoodsCollectionService;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.maiji.cloud.service.GoodsService;
import com.maiji.cloud.utils.RedisUtil;
import com.maiji.cloud.utils.UUID_MD5;
import org.apache.commons.lang.BooleanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
@Transactional
public class GoodsCollectionServiceImpl extends ServiceImpl<GoodsCollectionMapper, GoodsCollection> implements GoodsCollectionService {

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    @Autowired
    private UserInfoService userInfoService;
    @Autowired
    private GoodsService goodsService;

    @Override
    public BaseMetaResDto<List<GoodsResData>> findAllGoodsCollection(String token, ReqMetaData metaData) {
        AppUser appUser = RedisUtil.getAppUserByRedis(redisTemplate, MyRedisConfig.REDISDATABASENO, token, userInfoService);
        Wrapper<GoodsCollection> wrapper = new EntityWrapper<GoodsCollection>()
                .eq("user_id", appUser.getUuId())
                .eq("is_cancel", 0)
                .orderBy("collection_date", false);
        Page<GoodsCollection> page = selectPage(new Page<>(metaData.getPage(), metaData.getSize()), wrapper);
        ResMetaData resMetaData = new ResMetaData(page.getCurrent(), page.getSize(), page.getTotal());
        if (page.getTotal() == 0) return new BaseMetaResDto<List<GoodsResData>>(Status.SUCCESS).setResMetaData(resMetaData);
        List<String> goodsIds = page.getRecords().parallelStream().map(GoodsCollection::getGoodsId).collect(Collectors.toList());
        List<GoodsResData> goodsResDataList = Lists.newArrayList();
        if (goodsIds.size() > 0) {
            Map<String, GoodsResData> goodsResDataMap = goodsService.findAllGoodsResData(goodsService.selectBatchIds(goodsIds), token)
                    .parallelStream().collect(Collectors.toMap(GoodsResData::getUuId, GoodsResData::getThis));
            goodsResDataList = goodsIds.parallelStream().map(goodsId -> goodsResDataMap.get(goodsId)).collect(Collectors.toList());
        }
        return new BaseMetaResDto<List<GoodsResData>>(Status.SUCCESS).setData(goodsResDataList).setResMetaData(resMetaData);
    }

    @Override
    public GoodsCollection selectOneByRedis(String goods_id, String user_id) {
        String redisKey = RedisUtil.getRedisKey(REDISNAMESPACE, goods_id, user_id);
        GoodsCollection goodsCollection = (GoodsCollection) redisTemplate.opsForValue().get(redisKey);
        if (goodsCollection == null) {
            EntityWrapper<GoodsCollection> entityWrapper = new EntityWrapper<>();
            entityWrapper.eq("user_id", user_id);
            entityWrapper.eq("goods_id", goods_id);
            goodsCollection = selectOne(entityWrapper);
            if (goodsCollection != null) RedisUtil.setObject(redisTemplate, redisKey, goodsCollection);
        }
        return goodsCollection;
    }

    @Override
    public Boolean isCollection(String goodsId, String userId) {
        GoodsCollection goodsCollection = selectOneByRedis(goodsId, userId);
        if (goodsCollection == null) return false;
        else return ! BooleanUtils.toBoolean(goodsCollection.getIsCancel());
    }

    @Override
    public BaseResDto collectionGoodsById(String goodsId, String token) {
        AppUser appUser = RedisUtil.getAppUserByRedis(redisTemplate, MyRedisConfig.REDISDATABASENO, token, userInfoService);
        String userId = appUser.getUuId();
        Goods goods = goodsService.selectById(goodsId);
        GoodsCollection goodsCollection = selectOneByRedis(goodsId, userId);
        if (goodsCollection == null) {
            goodsCollection = new GoodsCollection().setUuId(UUID_MD5.getUUID()).setIsCancel(0)
                    .setGoodsId(goodsId).setUserId(userId).setCollectionDate(new Date());
            if (! insert(goodsCollection)) return new BaseResDto(Status.ERROR);
        } else {
            Integer isCancel = goodsCollection.getIsCancel();
            goodsCollection.setIsCancel(isCancel==1? 0: 1);
            if (! updateById(goodsCollection)) return new BaseResDto(Status.ERROR);
        }
        String redisKey = RedisUtil.getRedisKey(REDISNAMESPACE, goodsId, userId);
        RedisUtil.setObject(redisTemplate, redisKey, goodsCollection);
        Integer collectionNum = selectCount(new EntityWrapper<GoodsCollection>().eq("goods_id", goodsId));
        if (goodsService.updateById(goods.setCollectionVolume(collectionNum)))
            redisTemplate.delete(GoodsService.REDISNAMESPACE + goodsId);
        return new BaseResDto(Status.SUCCESS);
    }

    @Override
    public BaseResDto cancelCollectionGoods(List<String> goodsIds, String token) {
        AppUser appUser = RedisUtil.getAppUserByRedis(redisTemplate, MyRedisConfig.REDISDATABASENO, token, userInfoService);
        String userId = appUser.getUuId();
        EntityWrapper<GoodsCollection> entityWrapper = new EntityWrapper<>();
        entityWrapper.eq("user_id", userId);
        if (goodsIds == null || goodsIds.size() == 0)
            goodsIds = selectList(entityWrapper).parallelStream().map(GoodsCollection::getGoodsId).collect(Collectors.toList());
        if (goodsIds.size() == 0) return new BaseResDto(Status.SUCCESS);
        entityWrapper.in("goods_id", goodsIds);
        if (! delete(entityWrapper)) return new BaseResDto(Status.ERROR.setMessage("批量取消用户收藏商品失败"));
        List<String> goodsCollectionRedisKeys = goodsIds.parallelStream().map(goodsId ->
                RedisUtil.getRedisKey(REDISNAMESPACE, goodsId, userId)).collect(Collectors.toList());
        redisTemplate.delete(goodsCollectionRedisKeys);
       Wrapper<GoodsCollection> wrapper = new EntityWrapper<GoodsCollection>().in("goods_id", goodsIds)
                .eq("is_cancel", 0).setSqlSelect("goods_id, count(uu_id) collection").groupBy("goods_id");
        Map<String, Integer> cMap = selectMaps(wrapper).parallelStream().collect(Collectors.toMap(map ->
                (String) map.get("goods_id"), map -> Integer.valueOf(map.get("collection").toString())));
        List<Goods> goodsList = goodsService.selectBatchIds(goodsIds).parallelStream().map(goods ->
                goods.setCollectionVolume(cMap.get(goods.getUuId()))).collect(Collectors.toList());
        if (goodsService.updateBatchById(goodsList)) redisTemplate.delete(goodsIds.parallelStream()
                .map(goodsId -> RedisUtil.getRedisKey(GoodsService.REDISNAMESPACE, goodsId)).collect(Collectors.toList()));
        return new BaseResDto(Status.SUCCESS);
    }

}
